home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / tex / lametex_.z / lametex_ / lametex / src / Length.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-02  |  9.9 KB  |  342 lines

  1. /* Length.C
  2.  *
  3.  * The official LaTeX length parameters are implemented here. They control
  4.  * variables such as the paragraph indentation and the space to skip between
  5.  * lines.
  6.  *
  7.  * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
  8.  * edit and use as long as this copyright statement remains intact.
  9.  *
  10.  */
  11.  
  12. #include "Global.h"
  13. #include "Font.h"
  14. #include <string.h>
  15. #include <search.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18.  
  19. LengthParam::LengthParam(LengthParam *lp, Length *parent)
  20. {
  21.    _value = lp->_value;
  22.    _tokentext = lp->_tokentext;
  23.    _parent = parent;
  24. }
  25.  
  26. LengthParam::LengthParam(float value, char *tokentext, Length *parent)
  27. {
  28.    _value = value;
  29.    _tokentext = new char [strlen(tokentext)+1];
  30.    strcpy(_tokentext,tokentext);
  31.    _parent = parent;
  32. }
  33.  
  34. LengthParam::~LengthParam()
  35. {
  36.    delete _tokentext;
  37. }
  38.  
  39. int LengthParam::compare(const void *length1, const void *length2)
  40. {
  41.    LengthParam **len1;
  42.    LengthParam **len2;
  43.  
  44.    len1 = (LengthParam **) length1;
  45.    len2 = (LengthParam **) length2;
  46.  
  47.    return strcmp((*len1)->_tokentext, (*len2)->_tokentext);
  48. }
  49.  
  50. void LengthParam::set(float value)
  51. {
  52.    if(_value != value) {
  53.       if(value > _value && match("\\baselineskip"))
  54.      Global::files->readjust_vspace = value;
  55.       _value = value;
  56.       postscript_set();
  57.    }
  58. }
  59.  
  60. float LengthParam::get()
  61. {
  62.    return _value;
  63. }
  64.  
  65. void LengthParam::revert(Length *from)
  66. {
  67.    LengthParam **lp;
  68.    lp = from->fetch(_tokentext);
  69.    if(_value != (*lp)->get())
  70.       postscript_set();
  71. }
  72.  
  73. void LengthParam::postscript_set()
  74. {
  75.    LengthParam **lp;
  76.    Global::files->outfile << endl;
  77.  
  78.    if(match("\\baselineskip"))
  79.       Global::files->outfile << _value << " BASELINESKIP" << endl;
  80.    else if(match("\\parindent"))
  81.       Global::files->outfile << "/parindent " <<  _value << " def" << endl;
  82.    else if(match("\\parskip"))
  83.       Global::files->outfile << "/parskip " <<  _value << " def" << endl;
  84.    else if(match("\\textheight")) {
  85.        lp = _parent->fetch("\\topmargin");
  86.       Global::files->outfile << "/bottommargin "
  87.      << 684.0 - _value - (*lp)->get() << " def" << endl;
  88.    }
  89.    else if(match("\\textwidth") || match("\\linewidth")) {
  90.       lp = _parent->fetch("\\oddsidemargin");
  91.       Global::files->outfile << "/rightmargin "
  92.      << 540.0 - _value - (*lp)->get() << " def" << endl;
  93.    }
  94.    else if(match("\\topmargin")) {
  95.       Global::files->outfile << "/topmargin " << _value+108 << " def" << endl;
  96.       lp = _parent->fetch("\\textheight");
  97.       Global::files->outfile << "/bottommargin "
  98.      << 684.0 - _value - (*lp)->get() << " def" << endl;
  99.    }
  100.    else if(match("\\oddsidemargin") || match("\\evensidemargin")) {
  101.       Global::files->outfile << "/leftmargin " << _value+72 << " def" << endl;
  102.       lp = _parent->fetch("\\textwidth");
  103.       Global::files->outfile << "/rightmargin "
  104.      << 540.0 - _value - (*lp)->get() << " def" << endl;
  105.    }
  106. }
  107.  
  108. int LengthParam::match(char *tokentext)
  109. {
  110.    return !strcmp(_tokentext,tokentext);
  111. }
  112.  
  113. Length::Length()
  114. {
  115.    /* The LaTeX defaults for the LaTeX Length Parameters */
  116.    numvalues = 0;
  117.    makeparam( 12.0, "\\baselineskip");    // space between lines
  118.    makeparam(  1.0, "\\baselinestretch"); //  ditto, in units of lines
  119.    makeparam(126.0, "\\linewidth");       // same as textwidth
  120.    makeparam( 18.0, "\\parindent");       // paragraph indentation
  121.    makeparam(  0.0, "\\parskip");         // space between paragraphs
  122.    makeparam(540.0, "\\textheight");      // height of the page
  123.    makeparam(360.0, "\\textwidth");       // width of the page
  124.    makeparam( 54.0, "\\topmargin");       // top margin
  125.    makeparam( 54.0, "\\oddsidemargin");   // left margin, basically
  126.    makeparam( 54.0, "\\evensidemargin");  // left margin, basically
  127.    makeparam( 21.4, "\\bigskipamount");   // big vertical skip
  128.    makeparam( 16.9, "\\medskipamount");   // medium vertical skip
  129.    makeparam( 14.5, "\\smallskipamount"); // small vertical skip
  130.    makeparam( 28.34,"cm");                // centimeters (28 pts)
  131.    makeparam( 10.0, "em");                // width of letter M in current font
  132.    makeparam(  8.0, "ex");                // width of letter X in current font
  133.    makeparam( 72.0, "in");                // inches (72 pts)
  134.    makeparam( 12.0, "pc");                // Picas (1pc = 12pt)
  135.    makeparam(  1.0, "pt");                // Points
  136.    makeparam(  2.83,"mm");                // millimeters
  137.    for(int x=0; x < numvalues; x++)  // Initialize the variables
  138.       postscript_set(x);
  139. }
  140.  
  141. /* The class Length contains an array of pointers. The automatic definition
  142.  * created by the C++ compiler just copies over these pointers to the new
  143.  * Length. But we want the new Length being created to actually have copies
  144.  * of all the LengthParams in *values[], not pointers to the same ones!
  145.  * So an explicit definition is written here.
  146.  */
  147. Length::Length(Length *base)
  148. {
  149.    numvalues = base->numvalues;
  150.    for(int index=0; index < numvalues; index++)
  151.       values[index] = new LengthParam(base->values[index], this);
  152. }
  153.  
  154. Length::~Length()
  155. {
  156.    for(int x=0; x < numvalues; x++)
  157.       delete values[x];
  158. }
  159.  
  160. Param *Length::copy()
  161. {
  162.    return new Length(this);
  163. }
  164.  
  165. // Fetches the LengthParam in array values with given name
  166. LengthParam **Length::fetch(char *tokenstr)
  167. {
  168.    LengthParam key(0.0, tokenstr, this);
  169.    LengthParam *keyptr = &key;
  170.    LengthParam **keyptrptr = &keyptr;
  171.    LengthParam **lp = (LengthParam **)
  172.       bsearch((char *)keyptrptr, (char *) values,
  173.           numvalues, sizeof(LengthParam *), LengthParam::compare);
  174.    return lp;
  175. }
  176.  
  177. void Length::makeparam(float value, char *tokentext)
  178. {
  179.    values[numvalues++] = new LengthParam(value, tokentext, this);
  180.    qsort((char*)values, numvalues,
  181.      sizeof(LengthParam *), LengthParam::compare);
  182. }
  183.  
  184. void Length::set_lp(LengthParam *lp, float value)
  185. {
  186.    LengthParam **skip;
  187.    lp->set(value);
  188.    if(lp->match("\\baselinestretch")) {
  189.       skip = fetch("\\baselineskip");
  190.       float fontsize = Stack::get(Environment::PFont, Font::Size, "");
  191.       (*skip)->set(value * fontsize * 1.2);  // 1.2 is magic spacing number
  192.    } else if(lp->match("\\oddsidemargin")) {
  193.       skip = fetch("\\evensidemargin");
  194.       (*skip)->set(value);
  195.    } else if(lp->match("\\evensidemargin")) {
  196.       skip = fetch("\\oddsidemargin");
  197.       (*skip)->set(value);
  198.    }
  199. }
  200.  
  201. // Set the value of the LengthParam in the values array with given name
  202. // to the given value. Returns success boolean.
  203. int Length::set(int, float value, char *tokentext)
  204. {
  205.    LengthParam **lp;
  206.    if((lp=fetch(tokentext)) == NULL)
  207.       return FALSE;
  208.  
  209.    set_lp(*lp,value);
  210.    return TRUE;
  211. }
  212.  
  213. float Length::get(int subtype, char *tokentext)
  214. {
  215.    if(subtype == Parse_Length)
  216.       return length_argument();
  217.  
  218.    LengthParam **lp;   // Get parameter value
  219.    if((lp=fetch(tokentext)) == NULL) {
  220.       char message[MAXSTRING];
  221.       sprintf(message, "No length parameter %s defined", tokentext);
  222.       Global::files->fatal_error(message);
  223.    }
  224.    return (*lp)->get();
  225. }
  226.  
  227. void Length::postscript_set(int index)
  228. {
  229.    values[index]->postscript_set();
  230. }
  231.  
  232. void Length::revert(Param *from)
  233. {
  234.    for(int index=0; index < numvalues; index++)
  235.       values[index]->revert((Length *)from);
  236. }
  237.  
  238. /* Parses an argument between braces to be used in a length function
  239.  * such as \addtolength and \setlength. Returns the length in points.
  240.  */
  241. float Length::length_argument()
  242. {
  243.    char *tokenname;
  244.    LengthParam **lp;
  245.    float val = 1.0;
  246.    Global::files->set_parsing_length(TRUE);
  247.    for(Token command; !command.match("}"); command = Token()) {
  248.       if(command.match(""))
  249.      continue;
  250.       tokenname = command.get_text();
  251.       if(tokenname[0] >= '0' && tokenname[0] <= '9'
  252.      || tokenname[0]=='-' || tokenname[0]=='.') {
  253.      float t;           // A number
  254.      sscanf(tokenname,"%f",&t);
  255.      val *= t;
  256.       } else {              // A variable
  257.      lp = fetch(tokenname);
  258.      if(!lp) {
  259.         char message[MAXSTRING];
  260.         sprintf(message, "Undefined length parameter %s", tokenname);
  261.         Global::files->fatal_error(message);
  262.      }
  263.      val *= (*lp)->get();
  264.       }
  265.    }
  266.    
  267.    Global::files->set_parsing_length(FALSE);
  268.    return val;
  269. }
  270.  
  271. void Length::addtolength(int, int, float, char *)
  272. {
  273.    Token openbrace;
  274.    if(!openbrace.match("{"))
  275.       Global::files->fatal_error(
  276.              "Expecting '{' after \\addtolength statement");
  277.    
  278.    Token lengthparam;
  279.    if(lengthparam.match("}"))
  280.       Global::files->fatal_error(
  281.             "Expecting lengthparam before closing '}' in \\addtolength");
  282.       
  283.    LengthParam **lp = fetch(lengthparam.get_text());
  284.  
  285.    Token closebrace;
  286.    if(!closebrace.match("}"))
  287.       Global::files->fatal_error(
  288.          "More than one word before closing '}' in \\addtolength");
  289.  
  290.    openbrace = Token();
  291.    if(!openbrace.match("{"))
  292.       Global::files->fatal_error(
  293.            "Expecting second '{' after \\addtolength statement");
  294.    
  295.    set_lp(*lp,(*lp)->get()+Length::length_argument());
  296. }
  297.  
  298. void Length::newlength(int, int, float, char *)
  299. {
  300.    Token openbrace;
  301.    if(!openbrace.match("{"))
  302.       Global::files->fatal_error("Expecting '{' after \\newlength statement");
  303.    
  304.    Token lengthparam;
  305.    if(lengthparam.match("}"))
  306.       Global::files->fatal_error(
  307.             "Expecting lengthparam before closing '}' in \\newlength");
  308.       
  309.    makeparam(0.0,lengthparam.get_text());
  310.  
  311.    Token closebrace;
  312.    if(!closebrace.match("}"))
  313.       Global::files->fatal_error(
  314.          "More than one word before closing '}' in \\newlength");
  315. }
  316.  
  317. void Length::setlength(int, int, float, char *)
  318. {
  319.    Token openbrace;
  320.    if(!openbrace.match("{"))
  321.       Global::files->fatal_error("Expecting '{' after \\setlength statement");
  322.    
  323.    Token lengthparam;
  324.    if(lengthparam.match("}"))
  325.       Global::files->fatal_error(
  326.             "Expecting lengthparam before closing '}' in \\setlength");
  327.  
  328.    LengthParam **lp = fetch(lengthparam.get_text());
  329.  
  330.    Token closebrace;
  331.    if(!closebrace.match("}"))
  332.       Global::files->fatal_error(
  333.          "More than one word before closing '}' in \\setlength");
  334.  
  335.    openbrace = Token();
  336.    if(!openbrace.match("{"))
  337.       Global::files->fatal_error(
  338.              "Expecting second '{' after \\setlength statement");
  339.    
  340.    set_lp(*lp,Length::length_argument());
  341. }
  342.